home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 422_02 / laptalk / xmodem.c < prev   
C/C++ Source or Header  |  1994-03-20  |  10KB  |  352 lines

  1. /*
  2.  * XMODEM file transfer module for LAPTALK...
  3.  *
  4.  * Copyright 1991-1994 Dave Dunfield
  5.  * All rights reserved.
  6.  *
  7.  * Permission granted for personal (non-commercial) use only.
  8.  *
  9.  * Compile with DDS MICRO-C compiler in 8086 TINY model.
  10.  *
  11.  * Compile command: cc xmodem -fop
  12.  */
  13. #include <stdio.h>
  14. #include <window.h>
  15. #include <comm.h>
  16.  
  17. /* Transfer status codes */
  18. #define    INIT        0        /* Initializing line */
  19. #define    RX            1        /* Receive packet */
  20. #define    TX            2        /* Transmitting packet */
  21. #define    TIMEOUT        3        /* Timeout occured */
  22. #define    RNAK        4        /* Nak received */
  23. #define    ERROR        5        /* Checksum/CRC error */
  24. #define ABORT        6        /* Abort request */
  25. #define    ENDF        7        /* End of file */
  26. #define    DUP            8        /* Duplicate packet */
  27. #define    SEQ            9        /* Out of sequence */
  28.  
  29. /* Line control codes */
  30. #define SOH            0x01    /* start of header */
  31. #define ACK            0x06    /* Acknowledge */
  32. #define NAK            0x15    /* Negative acknowledge */
  33. #define CAN            0x18    /* Cancel */
  34. #define EOT            0x04    /* end of text */
  35.  
  36. char *baudtext[] = {
  37.     "110", "300", "1200", "2400", "4800", "9600", "19200", "38400" };
  38.  
  39. unsigned baudvalue[] = {
  40.     _110, _300, _1200, _2400, _4800, _9600, _19200, _38400 };
  41.  
  42. unsigned baud=3, block_num = 0, rx_block, last_stat = 0,
  43.     size = 128, port = 1, ccount = 3;
  44.  
  45. char *status_text[] = {
  46.     "Initiate", "RX packet", "TX packet", "Timeout", "NAK received",
  47.     "Bad Packet", "Abort", "End of file", "Duplicate", "Sequence error" };
  48.  
  49. char *filename = 0, upload = -1, pause = 0, crc = -1, last_crc = -2,
  50.     fill = 'Z'-0x40;
  51.  
  52. FILE *fp;
  53.  
  54. unsigned crctable[256] = {
  55.     0x0000,  0x1021,  0x2042,  0x3063,  0x4084,  0x50a5,  0x60c6,  0x70e7,
  56.     0x8108,  0x9129,  0xa14a,  0xb16b,  0xc18c,  0xd1ad,  0xe1ce,  0xf1ef,
  57.     0x1231,  0x0210,  0x3273,  0x2252,  0x52b5,  0x4294,  0x72f7,  0x62d6,
  58.     0x9339,  0x8318,  0xb37b,  0xa35a,  0xd3bd,  0xc39c,  0xf3ff,  0xe3de,
  59.     0x2462,  0x3443,  0x0420,  0x1401,  0x64e6,  0x74c7,  0x44a4,  0x5485,
  60.     0xa56a,  0xb54b,  0x8528,  0x9509,  0xe5ee,  0xf5cf,  0xc5ac,  0xd58d,
  61.     0x3653,  0x2672,  0x1611,  0x0630,  0x76d7,  0x66f6,  0x5695,  0x46b4,
  62.     0xb75b,  0xa77a,  0x9719,  0x8738,  0xf7df,  0xe7fe,  0xd79d,  0xc7bc,
  63.     0x48c4,  0x58e5,  0x6886,  0x78a7,  0x0840,  0x1861,  0x2802,  0x3823,
  64.     0xc9cc,  0xd9ed,  0xe98e,  0xf9af,  0x8948,  0x9969,  0xa90a,  0xb92b,
  65.     0x5af5,  0x4ad4,  0x7ab7,  0x6a96,  0x1a71,  0x0a50,  0x3a33,  0x2a12,
  66.     0xdbfd,  0xcbdc,  0xfbbf,  0xeb9e,  0x9b79,  0x8b58,  0xbb3b,  0xab1a,
  67.     0x6ca6,  0x7c87,  0x4ce4,  0x5cc5,  0x2c22,  0x3c03,  0x0c60,  0x1c41,
  68.     0xedae,  0xfd8f,  0xcdec,  0xddcd,  0xad2a,  0xbd0b,  0x8d68,  0x9d49,
  69.     0x7e97,  0x6eb6,  0x5ed5,  0x4ef4,  0x3e13,  0x2e32,  0x1e51,  0x0e70,
  70.     0xff9f,  0xefbe,  0xdfdd,  0xcffc,  0xbf1b,  0xaf3a,  0x9f59,  0x8f78,
  71.     0x9188,  0x81a9,  0xb1ca,  0xa1eb,  0xd10c,  0xc12d,  0xf14e,  0xe16f,
  72.     0x1080,  0x00a1,  0x30c2,  0x20e3,  0x5004,  0x4025,  0x7046,  0x6067,
  73.     0x83b9,  0x9398,  0xa3fb,  0xb3da,  0xc33d,  0xd31c,  0xe37f,  0xf35e,
  74.     0x02b1,  0x1290,  0x22f3,  0x32d2,  0x4235,  0x5214,  0x6277,  0x7256,
  75.     0xb5ea,  0xa5cb,  0x95a8,  0x8589,  0xf56e,  0xe54f,  0xd52c,  0xc50d,
  76.     0x34e2,  0x24c3,  0x14a0,  0x0481,  0x7466,  0x6447,  0x5424,  0x4405,
  77.     0xa7db,  0xb7fa,  0x8799,  0x97b8,  0xe75f,  0xf77e,  0xc71d,  0xd73c,
  78.     0x26d3,  0x36f2,  0x0691,  0x16b0,  0x6657,  0x7676,  0x4615,  0x5634,
  79.     0xd94c,  0xc96d,  0xf90e,  0xe92f,  0x99c8,  0x89e9,  0xb98a,  0xa9ab,
  80.     0x5844,  0x4865,  0x7806,  0x6827,  0x18c0,  0x08e1,  0x3882,  0x28a3,
  81.     0xcb7d,  0xdb5c,  0xeb3f,  0xfb1e,  0x8bf9,  0x9bd8,  0xabbb,  0xbb9a,
  82.     0x4a75,  0x5a54,  0x6a37,  0x7a16,  0x0af1,  0x1ad0,  0x2ab3,  0x3a92,
  83.     0xfd2e,  0xed0f,  0xdd6c,  0xcd4d,  0xbdaa,  0xad8b,  0x9de8,  0x8dc9,
  84.     0x7c26,  0x6c07,  0x5c64,  0x4c45,  0x3ca2,  0x2c83,  0x1ce0,  0x0cc1,
  85.     0xef1f,  0xff3e,  0xcf5d,  0xdf7c,  0xaf9b,  0xbfba,  0x8fd9,  0x9ff8,
  86.     0x6e17,  0x7e36,  0x4e55,  0x5e74,  0x2e93,  0x3eb2,  0x0ed1,  0x1ef0 };
  87.  
  88. /*
  89.  * Main routine
  90.  */
  91. main(argc, argv)
  92.     int argc;
  93.     char *argv[];
  94. {
  95.     int i, j;
  96.     char *ptr, *buffer;
  97.  
  98.     for(i=1; i < argc; ++i) {
  99.         ptr = argv[i];
  100.         switch((toupper(*ptr++)<<8)|toupper(*ptr++)) {
  101.             case '-D' : upload = 0;    break;
  102.             case '-P' :    pause = -1;    break;
  103.             case '-C' :    crc = 0;    break;
  104.             case 'R=' :    size = atoi(ptr);    break;
  105.             case 'P=' : port = atoi(ptr);    break;
  106.             case 'F=' :    fill = atoi(ptr);    break;
  107.             case 'S=' :        /* Speed */
  108.                 for(j=0; j < (sizeof(baudtext)/2); ++j) {
  109.                     if(!strcmp(ptr, baudtext[j])) {
  110.                         baud = j;
  111.                         goto gobreak; } }
  112.                 abort("XMODEM: Unknown baud rate");
  113.             default :
  114.                 if(filename)
  115.                     abort("XMODEM: Too many operands");
  116.                 filename = argv[i];
  117.             gobreak: } }
  118.  
  119.     if(!filename)
  120.         abort("\nUse: XMODEM <filename> [-C -D -P R=size P=port F=value S=speed]\n\nCopyright 1991-1994 Dave Dunfield\nAll rights reserved.\n");
  121.  
  122.     buffer = malloc(size);
  123.  
  124.     wopen(15, 6, 50, 13, WSAVE|WCOPEN|WBOX1|0x70);
  125.     wcursor_off();
  126.  
  127.     wgotoxy(1, 1); printf("XMODEM %s of %s", upload ? "Upload" : "Download", filename);
  128.  
  129.     if(!(fp = fopen(filename, upload ? "rb" : "wb"))) {
  130.         wgotoxy(8, 5); wputs(" ** Unable to access file! **");
  131.         pause = -1;
  132.         goto doexit1; }
  133.  
  134.     Copen(port, baudvalue[baud], PAR_NO|STOP_1|DATA_8, SET_RTS|SET_DTR|OUTPUT_2);
  135.  
  136.     disable();
  137.     Cflags |= TRANSPARENT;
  138.     enable();
  139.  
  140.     wgotoxy(1, 3); printf("Record size    : %u", size);
  141.     wgotoxy(1, 5); printf("Blockcheck     :");
  142.     wgotoxy(1, 7); printf("Transfer status: %s", status_text[0]);
  143.     wgotoxy(1, 9); printf("Record count   : %u", block_num);
  144.  
  145.     if(!upload) {
  146.         Cputc(crc ? 'C' : NAK);
  147. upld:
  148.         update_status(i = get_record(buffer));
  149.         switch(i) {
  150.             case RX :
  151.                 if(rx_block == (++block_num & 255)) {
  152.                     fwrite(buffer, size, fp);
  153.                     Cputc(ACK);
  154.                     wgotoxy(18, 9); wprintf("%u", block_num);
  155.                     goto upld; }
  156.                 if(rx_block == (--block_num & 255)) {
  157.                     Cputc(ACK);
  158.                     update_status(DUP);
  159.                     goto upld;}
  160.                 update_status(SEQ);
  161.             case ERROR :
  162.                 do {
  163.                     if((i = get_char(1)) == -2)
  164.                         goto doabort; }
  165.                 while(i != -1);
  166.                 Cputc(NAK);
  167.                 goto upld;
  168.             case TIMEOUT :
  169.                 if(!block_num) {
  170.                     if(crc && ccount) {
  171.                         --ccount;
  172.                         Cputc('C');
  173.                         goto upld; }
  174.                     crc = 0; }
  175.                 Cputc(NAK);
  176.             default:
  177.                 goto upld;
  178.             case ENDF :
  179.                 Cputc(ACK);
  180.             doabort:
  181.             case ABORT: } }
  182.  
  183.     else {
  184. /* First, handshake for CRC option */
  185.         if(!crc)
  186.             goto dnl1;
  187.         crc = 0;
  188. dnl0:    switch(get_char(10)) {
  189.             default: goto dnl0;    
  190.             case 'C' :
  191.                 crc = -1;
  192.                 break;
  193.             case -2: Cputc(CAN); goto doexit;
  194.             case NAK :
  195.                 crc = 0; }
  196. dnl1:    if(j = fread(buffer, size, fp)) {
  197.             for(i=j; i < size; ++i)
  198.                 buffer[i] = fill;
  199. dnl2:        update_status(i = send_record(buffer));
  200.             switch(i) {
  201.                 case TX :
  202.                     wgotoxy(18, 9); wprintf("%u", ++block_num);
  203.                     goto dnl1;
  204.                 case RNAK :
  205.                 case TIMEOUT :
  206.                     goto dnl2;
  207.                 case ABORT :
  208.                     Cputc(CAN);
  209.                     goto doexit;
  210.             default: } }
  211.         else
  212.             update_status(ENDF);
  213. dnl3:    Cputc(EOT);
  214. dnl4:    switch(i = get_char(1)) {
  215.             case NAK :
  216.             case -1 : goto dnl3;
  217.             default : goto dnl4;
  218.             case -2 :
  219.             case ACK: } }
  220.  
  221. doexit:
  222.     fclose(fp);
  223.     Cclose();
  224.  
  225. doexit1:
  226.     if(pause) {
  227.         wgotoxy(10, 10);
  228.         wputs("<Press any key to proceed>");
  229.         wgetc(); }
  230.  
  231.     wclose();
  232. }
  233.  
  234. /*
  235.  * Update the status message
  236.  */
  237. update_status(msg)
  238.     int msg;
  239. {
  240.     if(msg != last_stat) {
  241.         wgotoxy(18, 7);
  242.         wputs(status_text[last_stat = msg]);
  243.         wcleol(); }
  244.     if(crc != last_crc) {
  245.         wgotoxy(18, 5);
  246.         wputs((last_crc = crc) ? "Crc" : "Checksum");
  247.         wcleol(); }
  248. }
  249.  
  250.  
  251. /*
  252.  * Send an XMODEM record
  253.  */
  254. send_record(data)
  255.     char *data;
  256. {
  257.     unsigned i, c, chk;
  258.  
  259.     Cputc(SOH);
  260.     Cputc(block_num+1);
  261.     Cputc(~(block_num+1));
  262.     for(i=chk=0; i < size; ++i) {
  263.         Cputc(c = *data++);
  264.         chk = crc ? crctable[chk >> 8] ^ (chk << 8) ^ c : chk + c; }
  265.     if(crc)
  266.         Cputc(chk >> 8);
  267.     Cputc(chk);
  268.  
  269.     for(;;) switch(get_char(1)) {
  270.         case -1     : return TIMEOUT;
  271.         case -2  :
  272.         case CAN : return ABORT;
  273.         case NAK : return RNAK;
  274.         case ACK : return TX;
  275.         case 'C' :
  276.             if(!block_num) {
  277.                 crc = -1;
  278.